﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Xml;
using ZXing;
using ZXing.Common;

namespace WebAssistant.Common
{
    public partial class ReportHelper
    {
        private static readonly string rootNode = "Report";

        //命名空间
        private static readonly string rd = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner";
        private static readonly string df = "http://schemas.microsoft.com/sqlserver/reporting/2016/01/reportdefinition/defaultfontfamily";

        /// <summary>
        /// 创建报表文件
        /// </summary>
        /// <param name="reportFileName">报表文件名称</param>
        /// <param name="version">xml版本</param>
        /// <param name="encoding">xml编码</param>
        /// <param name="standalone"></param>
        /// <param name="modelName">模型名称</param>
        /// <returns></returns>
        public static bool CreateRdlReport(string reportFileName, string version, string encoding, string standalone,string modelName)
        {
            bool isSuccess;
            string newModelName = StringHelper.ReplaceChar(".", "_", modelName);
            try
            {
                XmlDocument xmlDoc = new XmlDocument();
                XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration(version, encoding, standalone);
                XmlNode root = xmlDoc.CreateElement(rootNode);
                xmlDoc.AppendChild(xmlDeclaration);

                //添加 Report 属性
                XmlAttribute xmlAttribute1 = xmlDoc.CreateAttribute("MustUnderstand");
                xmlAttribute1.Value = "df";
                root.Attributes.Append(xmlAttribute1);

                XmlAttribute xmlAttribute2 = xmlDoc.CreateAttribute("xmlns");
                xmlAttribute2.Value = "http://schemas.microsoft.com/sqlserver/reporting/2016/01/reportdefinition";
                root.Attributes.Append(xmlAttribute2);

                XmlAttribute xmlAttribute3 = xmlDoc.CreateAttribute("xmlns:rd");
                xmlAttribute3.Value = rd;
                root.Attributes.Append(xmlAttribute3);

                XmlAttribute xmlAttribute4 = xmlDoc.CreateAttribute("xmlns:df");
                xmlAttribute4.Value = df;
                root.Attributes.Append(xmlAttribute4);

                // 添加 DataSources
                XmlElement DataSourcesElement = xmlDoc.CreateElement("DataSources");
                // 添加 DataSources > DataSource
                XmlElement DataSourceElement = xmlDoc.CreateElement("DataSource");
                XmlAttribute DataSourceName = xmlDoc.CreateAttribute("Name");
                DataSourceName.Value = "ds_" + newModelName;
                DataSourceElement.Attributes.Append(DataSourceName);
                

                // 添加 DataSources > DataSource > ConnectionProperties
                XmlElement ConnectionPropertiesElement = xmlDoc.CreateElement("ConnectionProperties");
                // 添加 DataSources > DataSource > ConnectionProperties > DataProvider
                XmlElement DataProviderElement = xmlDoc.CreateElement("DataProvider");
                DataProviderElement.InnerXml = "System.Data.DataSet";
                ConnectionPropertiesElement.AppendChild(DataProviderElement);
                // 添加 DataSources > DataSource > ConnectionProperties > ConnectString
                XmlElement ConnectStringElement = xmlDoc.CreateElement("ConnectString");
                ConnectStringElement.InnerXml = "/* Local Connection */";
                ConnectionPropertiesElement.AppendChild(ConnectStringElement);

                DataSourceElement.AppendChild(ConnectionPropertiesElement);

                DataSourcesElement.AppendChild(DataSourceElement);
                root.AppendChild(DataSourcesElement);

                //添加数据集 DataSets
                XmlElement DataSetsElement = xmlDoc.CreateElement("DataSets");
                //添加 DataSets > DataSet
                XmlElement DataSetElement = xmlDoc.CreateElement("DataSet");
                XmlAttribute DataSetNameAttribute = xmlDoc.CreateAttribute("Name");
                DataSetNameAttribute.Value = newModelName;
                DataSetElement.Attributes.Append(DataSetNameAttribute);

                //添加 DataSets > DataSet > Query
                XmlElement QueryElement = xmlDoc.CreateElement("Query");

                //添加 DataSets > DataSet > Query > DataSourceName
                XmlElement DataSourceNameElement = xmlDoc.CreateElement("DataSourceName");
                DataSourceNameElement.InnerXml = "ds_" + newModelName;
                QueryElement.AppendChild(DataSourceNameElement);

                //添加 DataSets > DataSet > Query > CommandText
                XmlElement CommandTextElement = xmlDoc.CreateElement("CommandText");
                //CommandTextElement.InnerXml = "SELECT * FROM " + newModelName;
                CommandTextElement.InnerXml = "/* Local Query */" ;
                QueryElement.AppendChild(CommandTextElement);

                DataSetElement.AppendChild(QueryElement);

                //添加 DataSets > DataSet > Fields
                XmlElement FieldsElement = xmlDoc.CreateElement("Fields");
                // 批量添加 DataSets > DataSet > Fields > Field
                string className = OdooRpcClient.Converters.ModelMapper.GetModelName(modelName)[0];
                Type type = ClassHelper.GetClassInstanceByClassName(className);
                //PropertyInfo[] propertyInfos = type.GetProperties();

                //PropertyInfo[] propertyInfos = type.GetProperties().OrderBy(x => x.Name);

                //按属性名称排序
                var propertyInfos = from p in type.GetProperties()
                            orderby p.Name ascending
                            select p;

                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    PropertyDescriptor pd = TypeDescriptor.GetProperties(type)[propertyInfo.Name];
                    DescriptionAttribute description = pd.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;

                    //添加 Field 节点
                    XmlElement FieldElement = xmlDoc.CreateElement("Field");
                    if (description.Description.Trim().Length > 0)
                    {
                        FieldElement.SetAttribute("Name", description.Description ); //Field 节点的 Name 属性
                    }
                    else
                    {
                        FieldElement.SetAttribute("Name", propertyInfo.Name); //Field 节点的 Name 属性
                    }
                        
                    // 添加 Field > rd:TypeName 节点
                    XmlElement TypeNameElement = xmlDoc.CreateElement("rd", "TypeName", rd);
                    //TypeNameElement.InnerXml = ConvertTypeName(propertyInfo.PropertyType); //:TODO待转换属性
                    //TypeNameElement.InnerXml = propertyInfo.PropertyType.ToString(); //:TODO待转换属性
                    TypeNameElement.InnerXml = ConvertTypeName(propertyInfo); //:TODO待转换属性
                    FieldElement.AppendChild(TypeNameElement);

                    // 添加 Field > DataField 节点
                    XmlElement DataFieldElement = xmlDoc.CreateElement("DataField");
                    DataFieldElement.InnerXml = propertyInfo.Name;
                    FieldElement.AppendChild(DataFieldElement);

                    FieldsElement.AppendChild(FieldElement);
                }

                DataSetElement.AppendChild(FieldsElement);
                
                DataSetsElement.AppendChild(DataSetElement);
                root.AppendChild(DataSetsElement);

                //添加 ReportSections
                XmlElement ReportSectionsElement = xmlDoc.CreateElement("ReportSections");

                //添加 ReportSections > ReportSection
                XmlElement ReportSectionElement = xmlDoc.CreateElement("ReportSection");
                //添加 ReportSections > ReportSection > Body
                XmlElement BodyElement = xmlDoc.CreateElement("Body");
                //添加 ReportSections > ReportSection > Body > Height
                XmlElement HeightElement = xmlDoc.CreateElement("Height");
                HeightElement.InnerXml = "297mm";
                BodyElement.AppendChild(HeightElement);
                ReportSectionElement.AppendChild(BodyElement);

                //添加 ReportSections > ReportSection > Width 
                XmlElement WidthElement = xmlDoc.CreateElement("Width");
                WidthElement.InnerXml = "210mm";
                ReportSectionElement.AppendChild(WidthElement);

                //添加 ReportSections > ReportSection > Page 
                XmlElement PageElement = xmlDoc.CreateElement("Page");
                ReportSectionElement.AppendChild(PageElement);

                ReportSectionsElement.AppendChild(ReportSectionElement);

                root.AppendChild(ReportSectionsElement);

                xmlDoc.AppendChild(root);
                xmlDoc.Save(reportFileName);
                isSuccess = true;
            }
            catch 
            {
                isSuccess = false;
            }
            return isSuccess;
        }

        public static ArrayList GetDataSetName(string reportPath)
        {
            ArrayList list =  new ArrayList();

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(reportPath);
            XmlNodeList nodeList = xmlDoc.GetElementsByTagName("DataSet");
            foreach (XmlNode node in nodeList)
            {
                list.Add(node.Attributes["Name"].Value);
            }
            return list;
        }

        public static string GetTableName(string reportPath)
        {
            string content = string.Empty;

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(reportPath);

            //添加命名空间
            XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(xmlDoc.NameTable);
            xmlNamespaceManager.AddNamespace("rd", rd);

            XmlNodeList element = xmlDoc.GetElementsByTagName("rd:TableName");
            foreach(XmlNode item in element)
            {
                content = item.InnerXml;
            }
            
            return content;
        }

        public static string GetObjectDataSourceType(string reportPath)
        {
            string content = string.Empty;

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(reportPath);

            //添加命名空间
            XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(xmlDoc.NameTable);
            xmlNamespaceManager.AddNamespace("rd", rd);

            XmlNodeList element = xmlDoc.GetElementsByTagName("rd:ObjectDataSourceType");
            foreach(XmlNode item in element)
            {
                content = item.InnerXml;
            }
            
            return content;
        }

        public static string CreateRdlReportString(string modelName)
        {
            string newModelName = StringHelper.ReplaceChar(".", "_", modelName);
            XmlDocument xmlDoc = new XmlDocument();

            XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
            XmlNode root = xmlDoc.CreateElement(rootNode);
            xmlDoc.AppendChild(xmlDeclaration);

            //添加 Report 属性
            XmlAttribute xmlAttribute1 = xmlDoc.CreateAttribute("MustUnderstand");
            xmlAttribute1.Value = "df";
            root.Attributes.Append(xmlAttribute1);

            XmlAttribute xmlAttribute2 = xmlDoc.CreateAttribute("xmlns");
            xmlAttribute2.Value = "http://schemas.microsoft.com/sqlserver/reporting/2016/01/reportdefinition";
            root.Attributes.Append(xmlAttribute2);

            XmlAttribute xmlAttribute3 = xmlDoc.CreateAttribute("xmlns:rd");
            xmlAttribute3.Value = rd;
            root.Attributes.Append(xmlAttribute3);

            XmlAttribute xmlAttribute4 = xmlDoc.CreateAttribute("xmlns:df");
            xmlAttribute4.Value = df;
            root.Attributes.Append(xmlAttribute4);

            // 添加 DataSources
            XmlElement DataSourcesElement = xmlDoc.CreateElement("DataSources");
            // 添加 DataSources > DataSource
            XmlElement DataSourceElement = xmlDoc.CreateElement("DataSource");
            XmlAttribute DataSourceName = xmlDoc.CreateAttribute("Name");
            DataSourceName.Value = "ds_" + newModelName;
            DataSourceElement.Attributes.Append(DataSourceName);

            // 添加 DataSources > DataSource > ConnectionProperties
            XmlElement ConnectionPropertiesElement = xmlDoc.CreateElement("ConnectionProperties");
            // 添加 DataSources > DataSource > ConnectionProperties > DataProvider
            XmlElement DataProviderElement = xmlDoc.CreateElement("DataProvider");
            DataProviderElement.InnerXml = "System.Data.DataSet";
            ConnectionPropertiesElement.AppendChild(DataProviderElement);
            // 添加 DataSources > DataSource > ConnectionProperties > ConnectString
            XmlElement ConnectStringElement = xmlDoc.CreateElement("ConnectString");
            ConnectStringElement.InnerXml = "/* Local Connection */";
            ConnectionPropertiesElement.AppendChild(ConnectStringElement);

            DataSourceElement.AppendChild(ConnectionPropertiesElement);

            DataSourcesElement.AppendChild(DataSourceElement);
            root.AppendChild(DataSourcesElement);

            //添加数据集 DataSets
            XmlElement DataSetsElement = xmlDoc.CreateElement("DataSets");
            //添加 DataSets > DataSet
            XmlElement DataSetElement = xmlDoc.CreateElement("DataSet");
            XmlAttribute DataSetNameAttribute = xmlDoc.CreateAttribute("Name");
            DataSetNameAttribute.Value = newModelName;
            DataSetElement.Attributes.Append(DataSetNameAttribute);

            //添加 DataSets > DataSet > Query
            XmlElement QueryElement = xmlDoc.CreateElement("Query");

            //添加 DataSets > DataSet > Query > DataSourceName
            XmlElement DataSourceNameElement = xmlDoc.CreateElement("DataSourceName");
            DataSourceNameElement.InnerXml = "ds_" + newModelName;
            QueryElement.AppendChild(DataSourceNameElement);

            //添加 DataSets > DataSet > Query > CommandText
            XmlElement CommandTextElement = xmlDoc.CreateElement("CommandText");
            //CommandTextElement.InnerXml = "SELECT * FROM " + newModelName;
            CommandTextElement.InnerXml = "/* Local Query */";
            QueryElement.AppendChild(CommandTextElement);

            DataSetElement.AppendChild(QueryElement);

            //添加 DataSets > DataSet > Fields
            XmlElement FieldsElement = xmlDoc.CreateElement("Fields");
            // 批量添加 DataSets > DataSet > Fields > Field
            string className = OdooRpcClient.Converters.ModelMapper.GetModelName(modelName)[0];
            Type type = ClassHelper.GetClassInstanceByClassName(className);

            //按属性名称排序
            var propertyInfos = from p in type.GetProperties()
                                orderby p.Name ascending
                                select p;

            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                PropertyDescriptor pd = TypeDescriptor.GetProperties(type)[propertyInfo.Name];
                DescriptionAttribute description = pd.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;

                //添加 Field 节点
                XmlElement FieldElement = xmlDoc.CreateElement("Field");
                if (description.Description.Trim().Length > 0)
                {
                    FieldElement.SetAttribute("Name", description.Description); //Field 节点的 Name 属性
                }
                else
                {
                    FieldElement.SetAttribute("Name", propertyInfo.Name); //Field 节点的 Name 属性
                }

                // 添加 Field > rd:TypeName 节点
                XmlElement TypeNameElement = xmlDoc.CreateElement("rd", "TypeName", rd);
                //TypeNameElement.InnerXml = ConvertTypeName(propertyInfo.PropertyType); //:TODO待转换属性
                //TypeNameElement.InnerXml = propertyInfo.PropertyType.ToString(); //:TODO待转换属性
                TypeNameElement.InnerXml = ConvertTypeName(propertyInfo); //:TODO待转换属性
                FieldElement.AppendChild(TypeNameElement);

                // 添加 Field > DataField 节点
                XmlElement DataFieldElement = xmlDoc.CreateElement("DataField");
                DataFieldElement.InnerXml = propertyInfo.Name;
                FieldElement.AppendChild(DataFieldElement);

                FieldsElement.AppendChild(FieldElement);
            }

            DataSetElement.AppendChild(FieldsElement);
            DataSetsElement.AppendChild(DataSetElement);
            root.AppendChild(DataSetsElement);
            xmlDoc.AppendChild(root);

            return xmlToString(xmlDoc);
        }


        /// <summary>
        /// xml文件转换为字符串
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <returns></returns>
        public static string xmlToString(XmlDocument xmlDoc)
        {
            MemoryStream stream = new MemoryStream();
            XmlTextWriter writer = new XmlTextWriter(stream, null);
            writer.Formatting = Formatting.Indented;
            xmlDoc.Save(writer);
            StreamReader sr = new StreamReader(stream, System.Text.Encoding.UTF8);
            stream.Position = 0;
            string xmlString = sr.ReadToEnd();
            sr.Close();
            stream.Close();
            return xmlString;
        } 


        /// <summary>
        /// 转换字段属性类型
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        public static string ConvertTypeName(PropertyInfo property)
        {
            string typeString = property.PropertyType.ToString();
            if(StringHelper.GetCharInStringCount("[", typeString)>0){
                typeString = StringHelper.MidStrEx(typeString, "[", "]");
                if(StringHelper.GetCharInStringCount("OdooEnum", typeString) > 0){
                    typeString = "OdooRpcClient.OdooEnum";
                }
            }
            switch (typeString)
            {
                case "System.String":
                    return "System.String";
                case "System.Int32":
                    return "System.Int32";
                case "System.Int64":
                    return "System.Int32";
                case "System.Boolean":
                    return "System.String";
                case "OdooRpcClient.OdooEnum":
                    return "System.String";
                case "System.Double":
                    return "System.Double";
                case "System.Decimal":
                    return "System.Decimal";
                case "System.DateTime":
                    return "System.DateTime";
       
                default:
                    return "System.String";
            }
        }

        /// <summary>
        /// 毫米转像素
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        public static int MillimetersToPixelsWidth(double length)
        {
            System.Windows.Forms.Panel p = new System.Windows.Forms.Panel();
            System.Drawing.Graphics g = System.Drawing.Graphics.FromHwnd(p.Handle);
            IntPtr hdc = g.GetHdc();
            int width = GetDeviceCaps(hdc, 4);     // HORZRES 
            int pixels = GetDeviceCaps(hdc, 8);     // BITSPIXEL
            g.ReleaseHdc(hdc);
            return Convert.ToInt32((((double)pixels / (double)width) * (double)length));
        }
        [DllImport("gdi32.dll")]
        private static extern int GetDeviceCaps(IntPtr hdc, int Index);

        public static string GenerateBarcodeString(string barcodeValue,int height,int width)
        {
            try
            {
                if (barcodeValue != null)
                {
                    // 1.设置条形码规格
                    EncodingOptions encodeOption = new EncodingOptions();

                    encodeOption.Height = MillimetersToPixelsWidth(height); // 必须制定高度、宽度(像素)
                    encodeOption.Width = MillimetersToPixelsWidth(width);
                    encodeOption.PureBarcode = false; // 是否是纯码，如果为 false，则会在图片下方显示数字


                    // 2.生成条形码图片
                    BarcodeWriter wr = new BarcodeWriter();
                    wr.Options = encodeOption;
                    wr.Format = BarcodeFormat.CODE_128;  // 这里可以设定条码的标准
                    Bitmap img = wr.Write(barcodeValue); // 生成图片

                    // 3. 转Base64
                    MemoryStream ms = new MemoryStream();
                    img.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                    byte[] arr = new byte[ms.Length]; ms.Position = 0;
                    ms.Read(arr, 0, (int)ms.Length); ms.Close();
                    return Convert.ToBase64String(arr);
                }
                else
                {
                    return null;
                }
            }
            catch
            {
                return null;
            }
        }

        
    }
}
